import type { ResponseData } from '@/types/http'

const BASE_URL = import.meta.env.VITE_APP_BASE_API
const TIMEOUT = 60000 // 请求超时时间

// 请求拦截器
function requestInterceptor(options: UniApp.RequestOptions) {
  const token = uni.getStorageSync('token')

  // 合并请求配置
  const defaultOptions = {
    timeout: TIMEOUT,
    header: {
      'Content-Type': 'application/json',
      'Authorization': token,
    },
  }

  return {
    ...defaultOptions,
    ...options,
    url: `${BASE_URL}${options.url}`,
  }
}

// 响应拦截器
function responseInterceptor<T>(response: UniApp.RequestSuccessCallbackResult) {
  const resData = response.data as ResponseData<T>

  // 处理业务状态码
  if (resData.code === '00000') {
    return resData.data
  }

  // 处理特定错误码
  switch (resData.code) {
    case '401':
      // token过期，清除token并跳转登录页
      uni.removeStorageSync('token')
      uni.navigateTo({ url: '/pages/login/index' })
      break
    default:
      uni.showToast({
        title: resData.msg || '业务处理失败',
        icon: 'none',
        duration: 2000,
      })
  }

  return Promise.reject({
    message: resData.msg || '业务处理失败',
    code: resData.code,
  })
}

export function request<T>(options: UniApp.RequestOptions): Promise<T> {
  return new Promise((resolve, reject) => {
    uni.request({
      ...requestInterceptor(options),
      success: (response) => {
        try {
          const result = responseInterceptor<T>(response)
          resolve(result)
        }
        catch (error) {
          reject(error)
        }
      },
      fail: (error) => {
        uni.showToast({
          title: '网络请求失败',
          icon: 'none',
          duration: 2000,
        })
        reject({
          message: '网络请求失败',
          error,
        })
      },
    })
  })
}

// 导出常用请求方法
export const defHttp = {
  get<T>(url: string, params?: any, options?: Partial<UniApp.RequestOptions>): Promise<T> {
    return request<T>({
      ...options,
      url,
      method: 'GET',
      data: params,
    })
  },

  post<T>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>): Promise<T> {
    return request<T>({
      ...options,
      url,
      method: 'POST',
      data,
    })
  },

  put<T>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>): Promise<T> {
    return request<T>({
      ...options,
      url,
      method: 'PUT',
      data,
    })
  },

  delete<T>(url: string, data?: any, options?: Partial<UniApp.RequestOptions>): Promise<T> {
    return request<T>({
      ...options,
      url,
      method: 'DELETE',
      data,
    })
  },
}
